using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Data;
using ResourceBlender_Express.Properties;
using System.Data.Common;
using System.ComponentModel;

namespace ResourceBlender_Express {
    /// <summary>
    /// A window for managing applications
    /// </summary>
    public partial class WinApplications : Window {
        /// <summary>
        /// Initializes a new <see cref="WinApplications"/>.
        /// </summary>
        public WinApplications() {
            InitializeComponent();
            Database db = new Database();
            db = new Database();
            lstApplications.Items.SortDescriptions.Add(new System.ComponentModel.SortDescription("ApplicationName", System.ComponentModel.ListSortDirection.Ascending));
        }

        /// <summary>
        /// Loads the list of applications.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void Window_Loaded(object sender, RoutedEventArgs e) {
            LoadApplications();
        }

        /// <summary>
        /// Refreshed the list of applications.
        /// </summary>
        private void LoadApplications() {
            BackgroundWorker worker = new BackgroundWorker();
            WinProgress progress = new WinProgress("Loading applications...", true);
            worker.DoWork += (s, dwe) => {
                Database db = new Database();
                try {
                    dwe.Result = db.LoadApplications();
                } catch(Exception ex) {
                    dwe.Result = "Error connecting to the database: " + ex.Message;
                } finally {
                    if(db != null) {
                        try {
                            db.CloseConnection();
                        } catch { }
                    }
                }
            };
            worker.RunWorkerCompleted += (s, rwe) => {
                progress.Close();
                if(rwe.Result != null && rwe.Result is string) {
                    MessageBox.Show(this, rwe.Result.ToString(), "Database Error", MessageBoxButton.OK, MessageBoxImage.Error);
                } else {
                    DataContext = rwe.Result as List<RBApplication>;
                }
            };
            progress.Show();
            worker.RunWorkerAsync();
        }

        /// <summary>
        /// Shows a window to add a new application.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void AddApplication(object sender, ExecutedRoutedEventArgs e) {
            WinAddApplication dlg = new WinAddApplication();
            if(dlg.ShowDialog() == true) {
                BackgroundWorker worker = new BackgroundWorker();
                WinProgress progress = new WinProgress("Saving application...", true);
                worker.DoWork += (s, dwe) => {
                    Database db = new Database();
                    try {  
                        db.OpenConnection();
                        RBApplication app = dlg.Application;
                        using(Database.Command cmd = db.CreateCommand()) {
                            string appId = Utils.GenID(true);
                            cmd.CommandText = "INSERT INTO " + db.TablePrefix + "applications (id, name, displayname, defaultlanguage, languages) VALUES (@id, @name, @displayname, @defaultlanguage, @languages)";
                            cmd.AddParameterWithValue("@id", appId);
                            cmd.AddParameterWithValue("@name", app.ApplicationName);
                            cmd.AddParameterWithValue("@displayname", app.DisplayName);
                            cmd.AddParameterWithValue("@defaultlanguage", app.DefaultLanguage);
                            cmd.AddParameterWithValue("@languages", Utils.Implode(app.Languages, ",", false));
                            cmd.ExecuteNonQuery();

                            cmd.Parameters.Clear();

                            // no need for switch, if an application is being added, no bundles could have existed already
                            cmd.CommandText = string.Format("INSERT INTO {0}bundles (id, name, application) VALUES (@id, @name, @application)", db.TablePrefix);
                            cmd.AddParameterWithValue("@id", string.Empty);
                            cmd.AddParameterWithValue("@name", string.Empty);
                            cmd.AddParameterWithValue("@application", appId);
                            foreach(KeyValuePair<string, ChangeableBundle> bundle in dlg.Bundles) {
                                cmd.Parameters["@id"].Value = bundle.Value.ID;
                                cmd.Parameters["@name"].Value = bundle.Value.Name;
                                cmd.ExecuteNonQuery();
                            }
                        }
                    } catch(Exception ex) {
                        dwe.Result = "Error #450: Could not add application - " + ex.Message;
                    }
                };
                worker.RunWorkerCompleted += (s, rwe) => {
                    progress.Close();
                    if(rwe.Result != null) {
                        MessageBox.Show(this, rwe.Result.ToString(), "Database Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                    LoadApplications();
                };
                progress.Show();
                worker.RunWorkerAsync();    
            }
        }

        /// <summary>
        /// Starts editing an application.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>
        private void lstApplications_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
            ResourceBlenderCommands.Edit.Execute(null, this);
        }

        /// <summary>
        /// Determines whether the edit application command can be executed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
        private void CanExecuteEditApplication(object sender, CanExecuteRoutedEventArgs e) {
            e.CanExecute = lstApplications != null && lstApplications.SelectedItem != null;
            e.Handled = true;
        }

        /// <summary>
        /// Shows a window to edit an application.
        /// </summary>
        private void EditApplication(object sender, ExecutedRoutedEventArgs e) {
            if(lstApplications.SelectedValue == null)
                return;
            RBApplication originalApp = lstApplications.SelectedValue as RBApplication;
            WinAddApplication dlg = new WinAddApplication(originalApp.Clone());
            if(dlg.ShowDialog() == true) {
                BackgroundWorker worker = new BackgroundWorker();
                WinProgress progress = new WinProgress("Saving application...", true);
                worker.DoWork += (s, dwe) => {
                    Database db = new Database();
                    try {
                        db.OpenConnection();
                        using(Database.Command cmd = db.CreateCommand()) {
                            RBApplication app = dlg.Application;
                            cmd.CommandText = "UPDATE " + db.TablePrefix + "applications SET name = @name, displayname = @displayname, defaultlanguage = @defaultlanguage, languages = @languages WHERE id = @id";
                            cmd.AddParameterWithValue("@id", app.ID);
                            cmd.AddParameterWithValue("@name", app.ApplicationName);
                            cmd.AddParameterWithValue("@displayname", app.DisplayName);
                            cmd.AddParameterWithValue("@defaultlanguage", app.DefaultLanguage);
                            cmd.AddParameterWithValue("@languages", Utils.Implode(app.Languages, ",", false));
                            cmd.ExecuteNonQuery();

                            cmd.Parameters.Clear();

                            cmd.AddParameterWithValue("@id", string.Empty);
                            cmd.AddParameterWithValue("@name", string.Empty);
                            cmd.AddParameterWithValue("@application", app.ID);
                            foreach(KeyValuePair<string, ChangeableBundle> bundle in dlg.Bundles) {
                                try {
                                    switch(bundle.Value.Mode) {
                                        case ChangeableBundle.ChangeMode.Add:
                                            cmd.CommandText = string.Format("INSERT INTO {0}bundles (id, name, application) VALUES (@id, @name, @application)", db.TablePrefix);
                                            cmd.Parameters["@id"].Value = bundle.Value.ID;
                                            cmd.Parameters["@name"].Value = bundle.Value.Name;
                                            break;
                                        case ChangeableBundle.ChangeMode.Edit:
                                            cmd.CommandText = string.Format("UPDATE {0}bundles SET name = @name WHERE id = @id", db.TablePrefix);
                                            cmd.Parameters["@id"].Value = bundle.Value.ID;
                                            cmd.Parameters["@name"].Value = bundle.Value.Name;
                                            break;
                                        case ChangeableBundle.ChangeMode.Delete:
                                            cmd.CommandText = string.Format("DELETE FROM {0}bundles WHERE id = @id", db.TablePrefix);
                                            cmd.Parameters["@id"].Value = bundle.Value.ID;
                                            break;
                                        case ChangeableBundle.ChangeMode.None:
                                            continue;
                                    }
                                    cmd.ExecuteNonQuery();
                                } catch(Exception ex) {
                                    dwe.Result = "Error processing bundle: " + ex.Message;
                                }
                            }
                        }
                    } catch(Exception ex) {
                        dwe.Result = "Error connecting to the database: " + ex.Message;
                    } finally {
                        if(db != null) {
                            try {
                                db.CloseConnection();
                            } catch { }
                        }
                    }
                };
                worker.RunWorkerCompleted += (s, rwe) => {
                    progress.Close();
                    if(rwe.Result != null) {
                        MessageBox.Show(this, (rwe.Result ?? string.Empty).ToString(), "Database Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                    LoadApplications();
                };
                progress.Show();
                worker.RunWorkerAsync();
            }
        }

        /// <summary>
        /// Determines whether the delete application command can be executed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
        private void CanExecuteDeleteElement(object sender, CanExecuteRoutedEventArgs e) {
            e.CanExecute = lstApplications != null && lstApplications.SelectedItem != null;
            e.Handled = true;
        }

        /// <summary>
        /// Deletes an application after the user has confirmed.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void DeleteApplication(object sender, ExecutedRoutedEventArgs e) {
            if(lstApplications.SelectedValue == null)
                return;
            RBApplication app = lstApplications.SelectedValue as RBApplication;
            if(MessageBox.Show(this, string.Format("Are you sure you want to delete the application '{0}'?{1}{1} All bundles and elements contained within this application will also be deleted. Translations, will be not be deleted.", app.DisplayName, Environment.NewLine), "Confirm Delete", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) {
                BackgroundWorker worker = new BackgroundWorker();
                WinProgress progress = new WinProgress("Deleting application...", true);
                worker.DoWork += (s, dwe) => {
                    Database db = new Database();
                    try {
                        db.OpenConnection();
                        using(Database.Command cmd = db.CreateCommand()) {
                            cmd.CommandText = "DELETE FROM " + db.TablePrefix + "applications WHERE id = @p";
                            cmd.AddParameterWithValue("@p", app.ID);
                            cmd.ExecuteNonQuery();
                            cmd.CommandText = "DELETE FROM " + db.TablePrefix + "bundles WHERE application = @p";
                            cmd.ExecuteNonQuery();
                            cmd.CommandText = "DELETE FROM " + db.TablePrefix + "elements WHERE applicationid = @p";
                            cmd.ExecuteNonQuery();
                        }
                    } catch(Exception ex) {
                        dwe.Result = "Error connecting to the database: " + ex.Message;
                    } finally {
                        if(db != null) {
                            try {
                                db.CloseConnection();
                            } catch { }
                        }
                    }
                };
                worker.RunWorkerCompleted += (s, rwe) => {
                    progress.Close();
                    if(rwe.Result != null) {
                        MessageBox.Show(this, rwe.Result.ToString(), "Database Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                    LoadApplications();
                };
                progress.Show();
                worker.RunWorkerAsync();
            }
        }
    }
}
